﻿// MyProject.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//公众号：程序员速成 ，内含一辈子都让你感激自己的优质视频教程，欢迎关注

#include <iostream>
#include <queue>

#ifdef _DEBUG   //只在Debug（调试）模式下
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__) //重新定义new运算符
#define new DEBUG_NEW
#endif
#endif

//#include <boost/type_index.hpp>
using namespace std;
//#pragma warning(disable : 4996) 

namespace _nmsp1
{
	//日志文件操作相关类
	class LogToFile
	{
	public:
		void initfile()
		{
			//做日志文件初始化工作，比如打开文件等等
			//.....
		}
		void writetofile(const char* pcontent)
		{
			//将日志内容写入文件
			//......
		}
		void readfromfile()
		{
			//从日志中读取一些信息
			//......
		}
		void closefile()
		{
			//关闭日志文件
			//......
		}
		//.......可能还有很多其他成员函数，略
	};


	
	//---------------	
	//日志操作相关类（数据库版本）
	class LogToDatabase
	{
	public:
		void initdb()
		{
			//连接数据库，做一些基本的数据库连接设置等
			//......
		}
		void writetodb(const char* pcontent)
		{
			//将日志内容写入数据库
			//......
		}
		void readfromdb()
		{
			//从数据库中读取一些日志信息
			//......
		}
		void closedb()
		{
			//关闭到数据库的链接
			//......
		}
	};
	

	/*
	class LogToDatabase
	{
	public:
		virtual void initdb() = 0; //不一定非纯虚函数
		virtual void writetodb(const char* pcontent) = 0;
		virtual void readfromdb() = 0;
		virtual void closedb() = 0;

		virtual ~LogToDatabase() {} //做父类时析构函数应该为虚函数
	};
	//适配器类
	class LogAdapter :public LogToDatabase
	{
	public:
		//构造函数
		LogAdapter(LogToFile* pfile) //形参是老接口所属类的指针
		{
			m_pfile = pfile;
		}
		virtual void initdb()
		{
			cout << "在LogAdapter::initdb()中适配LogToFile::initfile()" << endl;
			//其中也可以加任何其他代码。。。。
			m_pfile->initfile();
		}
		virtual void writetodb(const char* pcontent)
		{
			cout << "在LogAdapter::writetodb()中适配LogToFile::writetofile()" << endl;
			//......
			m_pfile->writetofile(pcontent);
		}
		virtual void readfromdb()
		{
			cout << "在LogAdapter::readfromdb()中适配LogToFile::readfromfile()" << endl;
			m_pfile->readfromfile();
		}
		virtual void closedb()
		{
			cout << "在LogAdapter::closedb()中适配LogToFile::closefile()" << endl;
			m_pfile->closefile();
		}

	private:
		LogToFile* m_pfile;
	};
	*/

	//类适配器
	class LogAdapter :public LogToDatabase, private LogToFile
	{
	public:
		void initdb()
		{
			cout << "在LogAdapter::initdb()中适配LogToFile::initfile()" << endl;
			//其中也可以加任何其他代码。。。。
			initfile();
		}
		void writetodb(const char* pcontent)
		{
			cout << "在LogAdapter::writetodb()中适配LogToFile::writetofile()" << endl;
			//......
			writetofile(pcontent);
		}
		void readfromdb()
		{
			cout << "在LogAdapter::readfromdb()中适配LogToFile::readfromfile()" << endl;
			readfromfile();
		}
		void closedb()
		{
			cout << "在LogAdapter::closedb()中适配LogToFile::closefile()" << endl;
			closefile();
		}
	};
}

//class ParClass { ...... };
//class LogToFile:public ParClass{......};
//ParClass* m_pfile;

int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口

	//第15章 适配器（Adapter）模式：结构型模式
	//（1）一个简单的范例
	//有一天，意外情况/特殊需求
	//a)机房断电导致数据库中的数据发生了损坏无法正确读写，或者网络电缆遭到破坏导致数据库无法成功连接。
	//b)要从以往使用LogToFile类所生成的日志文件中读取一些日志信息。
	//制约因素：
	//a)LogToFile类实现源码很复杂,迁移功能到LogToDatabase类需要很久时间，影响业务。
	//b)LogToFile库提供给项目使用。源码拿不到（只能使用，不能修改）。
	//对一种接口的调用转换成对另外一种接口的调用，说明：
	//a)存在转换的可能
	//b)转换很可能不是一对一，而是一对多。可能转换起来很复杂

	//（2）引入适配器（Adapter）模式
	//定义（实现意图）：将一个类的接口转换成客户希望的另外一个接口。该模式使得原本接口不兼容而不能一起工作的类可以一起工作。
	  //适配器模式 别名 包装器（Wrapper）
	//三种角色：
	//a)Target(目标抽象类），LogToDatabase类
	//b)Adaptee（适配者类），LogToFile 类
	//c)Adapter（适配器类），LogAdapter类。
	
	//适配器模式-装饰模式。


	//（3）类适配器
	//a)对象适配器(LogToAdapter类)  b)类适配器

	//（4）适配器模式的扩展运用
	//c++标准库:容器适配器、算法（函数）适配器、迭代器适配器：把一个既有的东西进行适当改造比如增加或者减少一点东西就成为了一个适配器。
	//容器适配器：deque，stack,queue
	//算法适配器：std::bind(绑定器)
	//迭代器适配器：reverse_iterator（反向迭代器），对iterator的一层简单封装。










	//_nmsp1::LogToFile* plog = new _nmsp1::LogToFile();
	//plog->initfile();
	//plog->writetofile("向日志文件中写入一条日志"); //写一条日志到日志文件中
	//plog->readfromfile();
	//plog->closefile();
	//delete plog;

	/*
	_nmsp1::LogToDatabase* plogdb = new _nmsp1::LogToDatabase();
	plogdb->initdb();
	plogdb->writetodb("向数据库中写入一条日志"); //写一条日志到数据库中
	plogdb->readfromdb();
	plogdb->closedb();
	delete plogdb;
	*/

	/*
	_nmsp1::LogToFile* plog2 = new _nmsp1::LogToFile();
	_nmsp1::LogToDatabase* plogdb2 = new _nmsp1::LogAdapter(plog2);
	plogdb2->initdb();
	plogdb2->writetodb("向数据库中写入一条日志，实际是向日志文件中写入一条日志"); 
	plogdb2->readfromdb();
	plogdb2->closedb();
	delete plogdb2;
	delete plog2;
	*/

	_nmsp1::LogAdapter* plogdb3 = new _nmsp1::LogAdapter();
	plogdb3->initdb();
	plogdb3->writetodb("向数据库中写入一条日志，实际是向日志文件中写入一条日志");
	plogdb3->readfromdb();
	plogdb3->closedb();
	delete plogdb3;

	return 0;
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件

